import { createApp } from "vue"
import App from "@/App.vue"
import { createPinia } from "pinia"
import {
  createRouter,
  createWebHashHistory,
  createWebHistory,
} from "vue-router"

// import Box from "@/components/Box.vue"

// 创建应用实例
/* 
  createApp()
    - 用来创建一个应用实例
    - 参数：
        需要一个根组件作为参数
*/
const app = createApp(App)

const pinia = createPinia()
app.use(pinia)
pinia.use(({ store, app, pinia, options }) => {
  console.log(options)

  if (store.$id === "student") {
    store.$subscribe(() => {
      console.log("student发生变化了！！！")
    })
  }

  return {
    key: "哈哈哈哈哈哈",
  }
})
/* 
  createRouter()
    - 用来创建路由实例，需要一个对象作为参数
        history 用来指定路由的风格
        routes 路由表
    - history 用来指定路由的风格（路由的模式）
        createWebHistory() 传统模式，和传统项目的地址类似（推荐的方式）
          - 项目部署到生产环境时，必须要对服务器进行配置
              所有的向服务器发送的请求，都要重写到/index.html

        createWebHashHistory() 使用hash值来设置路由
          - 无需对服务器进行配置

    - routes 路由表
      - 需要一个数组作为参数，每一个路由的信息就是一个对象
      - 对象：
        path
          - 路由的路径
          - 规则：
            1.静态路径
              - 静态路径要求访问路径和路由完全匹配
                /path --> /path
                      --> /path/ strict: true 可以禁止结尾/
                      --> /Path sensitive: true 可以严格区分大小写

              - 参数：
                1. 查询字符串

            2.动态路径
              - 动态路径是不固定
              - 语法：/path/:param --> /path/xxx
              - 支持：? 0-1次
                     * 0-n次
                     + 1次以上
              
            3.正则表达式
              - 在动态路径中可以通过正则表达式对路径做更详细的限制

    路由的地址在vue-router中都会有一个分数，
      分数越高的越优先，分数一样的看顺序

    分数大小：
      根目录 > 静态路径 > 动态路径（带正则）> 动态路径
      strict 和 sensitive会少量加分

      + * ? 会减分
      .     会减分

      component:
        - 路径所映射的组件，当路径被访问时组件会被渲染
        - 接收的值：
            1.可以直接接收一个组件
              - 这样所有的组件都会在项目初始化时被导入
              - 这样会导致初次加载项目时过慢
            2.可以设置一个函数为值
              () => import("@/pages/Home.vue")
              - 这样组件只会在需要时才加载，提升页面加载速度
      components
        - 路径所映射的组件，可以为命名视图来指定组件
          <RouterView name="footer"></RouterView>
          <RouterView></RouterView>
          components: {
            default: () => import("@/pages/About.vue"),
            footer: () => import("@/pages/Home.vue"),
          }

      children
        - 嵌套路由，需要一个数组作为参数
        - children: [
            {
              path: "info", // /users/info
              component: () => import("@/pages/users/UserInfo.vue"),
              name: "info",
            },
            {
              path: "",
              component: () => import("@/pages/users/UserList.vue"),
            },
          ],

        - 注意：
          1.子路由的path不需要/ 它会自动和父路由的path拼接
          2.子路由的path设置为空串，则会成为默认的子路由
          3.子路由会在父路由的路由视图中呈现
          4.也可以为子路由指定name属性
          5.如果通过父路由的name属性跳转，则不会触发默认子路由

      redirect
        - 重定向
        - 将一个请求地址重定向到另外的地址
        - 取值：
          1.路径
            redirect: "/home",
          2.对象
            redirect: {
              name: "home",
              query: {
                name: "猪八戒",
              },
            },
          3.函数
            redirect: (to) => {
              // 回调函数中会得到一个参数to
              // to表示当前目标路径
              return {
                path: "/home",
                query: to.params,
              }
            },
      alias
        - 路由的别名
        - alias: ["/", "/a", "/b"],
        - 通过别名通过可以匹配到当前的路由

      props
        - 可以将动态路径作为props传递给组件
        - 取值：
            1. props: true,
                - 自动将动态路径转换为props
                - 如果使用了命名视图，可以分别指定每个视图
                props: {
                  default: true,
                  footer: true,
                }
            2. props: { id: 180 },
                - 渲染组件时，自动将对象中的属性作为props传递
            3. props: (to) => {
                 return { id: to.params.id }
               },
                - 通过函数返回props
          
*/
const router = createRouter({
  history: createWebHistory(),
  routes: [
    {
      path: "/hello/:name",
      redirect: (to) => {
        // 回调函数中会得到一个参数to
        // to表示当前目标路径
        return {
          path: "/home",
          query: to.params,
        }
      },
    },
    {
      path: "/:pathMatch(.*)*",
      component: () => import("@/pages/Page404.vue"),
    },
    {
      path: "/home",
      component: () => import("@/pages/Home.vue"),
      strict: true,
      sensitive: true,
      name: "home",
      alias: ["/", "/a", "/b"],
    },
    {
      path: "/about",
      component: () => import("@/pages/About.vue"),
      beforeEnter: (to, from) => {
        console.log("beforeEnter.............")
      },
    },
    {
      path: "/users",
      component: () => import("@/pages/User.vue"),
      meta: {
        needAuth: true,
      },
      children: [
        {
          path: "info",
          component: () => import("@/pages/users/UserInfo.vue"),
          meta: {
            needAuth: false,
          },
        },
        {
          path: "list",
          component: () => import("@/pages/users/UserList.vue"),
        },
      ],
    },
  ],
})

/* 
  路由守卫
    - 路由守卫可以在路由跳转前对请求进行验证
    - 类型：
      全局路由守卫
        - 对所有的路由生效
          router.beforeEach() 每个路由跳转前都会执行
          router.afterEach() 路由跳转完成后执行，无法阻止路由的跳转
          router.beforeResolve() 组件渲染前

      独享路由守卫
        beforeEnter: (to, from) => {}, 进入路由前触发，主要用于设置一些特殊的权限认证

      组件内的守卫
        beforeRouteUpdate 路由组件的重新渲染（参数变了）
        beforeRouteLeave 路由组件卸载前触发，防止未保存的表单
*/
router.beforeEach((to, from) => {
  // to表示目标信息  from来源信息
  // console.log(from)
  // if (to.path === "/about") return { path: "/home", query: { name: "猪八戒" } }
  // 在路由守卫中，可以通过返回值来控制跳转
  // return false 终止跳转
  // 权限检查
  console.log("beforeEach")
  // meta可以为路由设置一些元数据，通过route可以访问到meta中的数据
  // meta是集合当前路由和其父路由的meta

  if (to.meta.needAuth) {
    return false
  }
})

router.afterEach((to, from) => {
  console.log("afterEach")
})

router.beforeResolve((to, from) => {
  console.log("beforeResolve...")
})

app.use(router)

// app.config.globalProperties.hello = "哈哈哈"

// app.component("Box", Box)

app.provide("hello", "通过应用实例提供的数据")

// 将应用实例挂载到页面中
app.mount("#app")
